/*
* ============================================================================
*  Name     : CLogExEngine from LogExEngine.h
*  Part of  : LogExample
*  Created  : 26.05.2005 by Forum Nokia  
*  Implementation notes:
*  Version  : 1.0
*  Copyright: Nokia Corporation
* ============================================================================*/

//INCLUDE FILES
#include <eikenv.h>
#include <logwrap.h>
#include <logwrap.hrh>

#include "e32math.h"	// Random()        

#include "LogExEngine.h"


//DEBUG
#include <e32cons.h>

//LOCAL_D CConsoleBase* gConsole;



// CONSTANTS
_LIT(KOwnEventDescription, "Bluetooth");
_LIT(KOwnEventDirection, "Bluetooth"); 
_LIT(KOwnEventNumber, "No number"); 
_LIT(KOwnEventSubject, "RandomLogEvent");
_LIT(KOwnEventRemoteParty, "OwnContact");
_LIT(KEngineRunPanicText,"Engine-RunL");
_LIT(KEngineAddRandomText,"Engine-AddRandom");
_LIT(KEngineAddOwnText, "Engine-AddOwn");
_LIT(KEngineDefaultSwitch, "Engine-CreateRandom");

const TUid KOwnEventTypeUid = {0x10005570};

// ====================== PUBLIC ============================


// ----------------------------------------------------------
// CLogExEngine::CLogExEngine():CActive(EPriorityStandard)
// Defines priority for object
// ----------------------------------------------------------
//	
CLogExEngine::CLogExEngine():CActive(EPriorityStandard)
	{
	}

// ----------------------------------------------------
// CLogExEngine::~CLogExEngine()
// Destructor
// Frees reserved resources
// ----------------------------------------------------
//
CLogExEngine::~CLogExEngine()
	{
	Cancel();
	
	delete iLogViewEvent;
	delete iLogViewRecent;
	delete iLogEventType;	
	delete iLogClient;	
	delete iLogEvent;
	delete iLogFilter;
	delete iEmptyLogFilter;	

	iFs.Close();
	}


// ----------------------------------------------------
// CLogExEngine::NewL()
// Symbian 2-phase constructor
// ----------------------------------------------------
//
CLogExEngine* CLogExEngine::NewL()
	{
	CLogExEngine* self = CLogExEngine::NewLC();
	CleanupStack::Pop(self);
	return self;
	}

// ----------------------------------------------------
// CLogExEngine::NewLC()
// Symbian 2-phase constructor
// ----------------------------------------------------
//
CLogExEngine* CLogExEngine::NewLC()
	{
	CLogExEngine* self = new (ELeave) CLogExEngine();
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}

// ================= PRIVATE ======================= 

// ----------------------------------------------------
// CLogExEngine::ConstructL()
// Symbian 2-phase constructor
// ----------------------------------------------------
//
void CLogExEngine::ConstructL()
	{
	
	User::LeaveIfError(iFs.Connect());
	
	// Establish connection to log engine
	iLogClient = CLogClient::NewL(iFs);
 
	// Log view and view for recent events events with standard priority
	iLogViewEvent = CLogViewEvent::NewL(*iLogClient);
	iLogViewRecent = CLogViewRecent::NewL(*iLogClient);

	// Filter for events
	iLogFilter = CLogFilter::NewL();
	iEmptyLogFilter = CLogFilter::NewL(); 
		
	iOwnEvenTypeRegistered = EFalse;

	iObserver = NULL;
	
	iTask = ESleep; // Default task for RunL
		
	CActiveScheduler::Add(this);
	
	}

// ----------------------------------------------------
// CLogExEngine::RunL()
// RunL
// ----------------------------------------------------
//
void CLogExEngine::RunL()
	{
		
	switch (iTask)
		{
		case ENoEvent:
			{
			if (!iLogViewEvent->CountL()) 
			{
			iTask=ESleep;
			if(iObserver)
				{
				iObserver->NotifyStopReadEventL(); 	
				}
			}	
			break;
			}
		case EGetEvent:
			{
			// Notify observer about change if it has been set
			if(iObserver)
				{
				iObserver->NotifyEventReadL(iLogViewEvent->Event()); 	
				}
			else
				{
				iTask = ESleep;
				break; // No observer, no need to do anything	
				}
				
			// if there are more events in the log engine database...
			if(iLogViewEvent->NextL(iStatus))
				{
				
				// ... set active to get the next one
				SetActive();
				}
			else // no more events
				{	
				iObserver->NotifyStopReadEventL();
				iTask = ESleep;
				}
			break;
			}
		
		case EGetRecent:
			{
		
			// Notify observer about change if it has been set
			// Event in the view is sent as a parameter
			if(iRecentObserver)
				{
				iRecentObserver->NotifyEventReadL(iLogViewRecent->Event()); 	
				}
				
			// if there are more events in the log engine database...
			if(iLogViewRecent->NextL(iStatus))
				{
				
				// ... set active to get the next one with the 
				// next asynchronous call
				SetActive();
				}
			else // no more events
				{				
				iTask = ESleep;
				}
			break;
			}
		
		case EAddEvent: // add event to the log engine database
			{
			
			// Event added to log engine database 
			// Notify of change
			__ASSERT_ALWAYS( (iLogEvent != 0), User::Panic(KEngineRunPanicText,1) );
			if(iObserver)
				{
				iObserver->NotifyEventAddedL(*iLogEvent);	
				}
			
			delete iLogEvent;
			iLogEvent = NULL;
			
			iTask = ESleep;
			break;
			}
		case EAddEventType:
			{	
			if(iStatus == KErrAlreadyExists) 
				{
				iOwnEvenTypeRegistered = ETrue; 
				}
		
			AddOwnEventL();
			break;
			}
		case EDeleteEvent:
			{
	
			// Inform observers about deleted event if necessary
			if(iObserver)
				{
				iObserver->NotifyEventDeletedL();				
				}
				
			iTask = ESleep;
			break;
			}
		case ESleep:
		default:
			{
			break;
			}			
		}	 
	}
	

// ----------------------------------------------------
// CLogExEngine::RunError()
// RunL can leave so we need to implement RunError method
// ----------------------------------------------------
//
TInt CLogExEngine::RunError(TInt anError)
	{
	return anError;
	}

// ----------------------------------------------------
// CLogExEngine::DoCancel()
// Method to cancel outstanding request
// ----------------------------------------------------
//
void CLogExEngine::DoCancel()
	{
	//Cancel appropriate request
	switch ( iTask )
		{
		case ENoEvent:
			{
			iLogViewEvent->Cancel();
			break;
			}
		case EGetEvent:
			{
			iLogViewEvent->Cancel();
			break;
			}
		
		case EGetRecent:
			{
			iLogViewRecent->Cancel();
			break;
			}
			
		case EAddEvent:
			{
			iLogClient->Cancel();
			break;
			}
			
		case EAddEventType:
			{
			iLogClient->Cancel();
			break;	
			}	
					
		case EDeleteEvent:
		    {
		    iLogClient->Cancel();	
		    break;
		    }
		    
		case ESleep:
		default:
			break;
		}
	}	

// ----------------------------------------------------
// CLogExEngine::DeleteEventL(TLogId& aLogId)
// Deletes event from the main event log - asynchronous call
// ----------------------------------------------------
//
void CLogExEngine::DeleteEventL(TLogId& aLogId)
	{
	Cancel();
	iLogClient->DeleteEvent(aLogId, iStatus);
	iTask = EDeleteEvent;
	SetActive();
	}

// ----------------------------------------------------
// CLogExEngine::SetObserver(MEventsObserver* aObserver)
// Sets events observer
// ----------------------------------------------------
//
void CLogExEngine::SetObserver(MEventsObserver* aObserver)
	{
	iObserver = aObserver;	
	}

// ----------------------------------------------------
// CLogExEngine::RemoveObserver()
// Removes current events observer
// ----------------------------------------------------
//
void CLogExEngine::RemoveObserver()
	{
	iObserver = NULL;		
	}
	
// ----------------------------------------------------
// CLogExEngine::SetRecentObserver(MEventsObserver* aObserver)
// Sets recent events observer
// ----------------------------------------------------
//	
void CLogExEngine::SetRecentObserver(MEventsObserver* aObserver)
	{
	iRecentObserver = aObserver;		
	}

// ----------------------------------------------------
// CLogExEngine::RemoveRecentObserver()
// Removes current resent events observer
// ----------------------------------------------------
//	
void CLogExEngine::RemoveRecentObserver()
	{
	iRecentObserver = NULL;		
	}

// ----------------------------------------------------
// CLogExEngine::SetEventFilterDirectionIncoming()
// Sets incoming events filtering
// ----------------------------------------------------
//
void CLogExEngine::SetEventFilterDirectionIncoming()
	{
	TBuf<KLogMaxDirectionLength> direction;
	iLogClient->GetString(direction, R_LOG_DIR_IN);
	ClearEventFilter();
	iLogFilter->SetDirection(direction);
	}

// ----------------------------------------------------
// CLogExEngine::SetEventFilterDirectionOutgoing()
// Sets outgoing events filtering
// ----------------------------------------------------
//
void CLogExEngine::SetEventFilterDirectionOutgoing()
	{
	TBuf<KLogMaxDirectionLength> direction;
	iLogClient->GetString(direction, R_LOG_DIR_OUT);
	ClearEventFilter();
	iLogFilter->SetDirection(direction);
	}

// ----------------------------------------------------
// CLogExEngine::SetEventFilterEventTypeVoice()
// Sets voice type events filtering
// ----------------------------------------------------
//
void CLogExEngine::SetEventFilterEventTypeVoice()
	{
	ClearEventFilter();
	iLogFilter->SetEventType(KLogCallEventTypeUid);
	}

// ----------------------------------------------------
// CLogExEngine::SetEventFilterEventTypeSMS()
// Sets sms events filtering
// ----------------------------------------------------
//
void CLogExEngine::SetEventFilterEventTypeSMS()
	{
	ClearEventFilter();
	iLogFilter->SetEventType(KLogShortMessageEventTypeUid); 
	}

// ----------------------------------------------------
// CLogExEngine::ClearEventFilter()
// Clears filter
// ----------------------------------------------------
//
void CLogExEngine::ClearEventFilter()
	{
	// Empty the active filter copying empty filter to it	
	iLogFilter->Copy(*iEmptyLogFilter);
	}

// ----------------------------------------------------
// CLogExEngine::ReadEventsL()
// Reads events from main event database
// ----------------------------------------------------
//
void CLogExEngine::ReadEventsL()
	{	
	Cancel();

	// ETrue if there are any events in the log view
	if(iLogViewEvent->SetFilterL(*iLogFilter,iStatus))
	{
		// set this active object active to get the events 
		// from the main event database, see RunL()
		iTask = EGetEvent;
		SetActive();
	}
//	else
//	{  // No any events in the log view
//		iTask=ENoEvent;
//		SetActive();
//	}
	// If there are no events in the main event database, 
	// do nothing and return
	}
	
// ----------------------------------------------------
// CLogExEngine::ReadRecentEventsL()
// Reads recents events from main event database
// ----------------------------------------------------
//
void CLogExEngine::ReadRecentEventsL()
	{	
	Cancel();

	// ETrue if there are any events in the log view
	if(iLogViewRecent->SetRecentListL(KLogNullRecentList, iStatus))
		{
		// set this active object active to get the events 
		// from the main event database, see RunL()
		iTask = EGetRecent;
		SetActive();
		}
	// If there are no events in the main event database, 
	// do nothing and return
	}

// ----------------------------------------------------
// CLogExEngine::AddRandomEventL()
// Adds random event to log engine database
// ----------------------------------------------------
//
void CLogExEngine::AddRandomEventL()
	{
	Cancel();
	
	__ASSERT_ALWAYS( (iLogEvent == 0), User::Panic(KEngineAddRandomText,1) );
		
	iLogEvent = CreateRandomLogEventL(); // create new random log event
			
	iTask = EAddEvent; // tell RunL to add the iLogEvent to the log engine database
	iLogClient->AddEvent(*iLogEvent, iStatus); // call asynchronous method to add the event
	
	SetActive();
	}

// ----------------------------------------------------
// CLogExEngine::AddEventTypeToLogEngineL()
// Adds own event to main event database
// ----------------------------------------------------
//
void CLogExEngine::AddEventTypeToLogEngineL()
	{
	if(iOwnEvenTypeRegistered) // if already registered, do nothing and return
	{
		return;
	}
		
	Cancel(); // possible requests pending
	iTask = EAddEventType; // set task type for RunL
	
	iLogEventType = OwnLogEventTypeL(); // create new event type
		
	// register new event type the main event database
	iLogClient->AddEventType(*iLogEventType, iStatus);
	
	SetActive();
	}

// ----------------------------------------------------
// CLogExEngine::AddOwnEventL()
// Adds own event to the log engine database
// ----------------------------------------------------
//
void CLogExEngine::AddOwnEventL()
	{
	Cancel();

	if(!iOwnEvenTypeRegistered)
		{
		AddEventTypeToLogEngineL();
		return;
		}
	
	__ASSERT_ALWAYS( (iLogEvent == 0), User::Panic(KEngineAddOwnText,1) );
		
	iLogEvent = CreateRandomLogEventL(); // create a new random log event
	
	// change information and Uid
	// Own eventtypes TUids must be different from those defined
	// in logeng.h. They also don't show up in the Log application. 
	iLogEvent->SetEventType(KOwnEventTypeUid);
	
	// Set own information for the event
		
	iLogEvent->SetDescription(KOwnEventDescription);
	iLogEvent->SetDirection(KOwnEventDirection);
	iLogEvent->SetNumber(KOwnEventNumber);
	
	iTask = EAddEvent; // tell RunL to add the iLogEvent to the log engine database
	iLogClient->AddEvent(*iLogEvent, iStatus); // call asynchronous method to add the event
	
	SetActive();
	}

// ----------------------------------------------------
// CLogExEngine::OwnLogEventTypeL()
// This is to demonstrate how to build up an own event type.
// ----------------------------------------------------
//
CLogEventType* CLogExEngine::OwnLogEventTypeL()
	{
	
	CLogEventType* owneventtype = CLogEventType::NewL();

	// Event type spesific TUid must be set 	
	const TUid KOwnEventTypeUid = {0x10005570};
	
	owneventtype->SetUid(KOwnEventTypeUid);
	owneventtype->SetDescription(KOwnEventDescription);
	
	// Make sure event type is logged
	owneventtype->SetLoggingEnabled(ETrue);

	return owneventtype;
	}


// ----------------------------------------------------
// CLogExEngine::CreateRandomLogEventL()
// creates a random new log event for emulator
// ----------------------------------------------------
//
CLogEvent* CLogExEngine::CreateRandomLogEventL()
	{
	CLogEvent* event = CLogEvent::NewL();

	// Sets the duration of the event in seconds.
	// Randomize something between 0-299 
	
	event->SetDuration(Random(300));
	
	TBuf<KLogMaxDirectionLength> direction;
	
	// Direction of the event is randomized
	
	TInt randomDirection = Random(2); // randomize direction
	TInt dirID = 0;
	
	
	switch (randomDirection)
	{
		case 0:
			dirID = R_LOG_DIR_IN;
			break;
		case 1:
			dirID = R_LOG_DIR_OUT;
			break;
		default:
            break; 
	}
	
	// Human readable presentations of directions
	// with CLogClient::GetString()-method
	
	iLogClient->GetString(direction, dirID);
	
	// Set the direction
	
	event->SetDirection(direction);
	
	TInt randomEventType = Random(6); // randomize event type
	
	TUid eventTypeID = KLogCallEventTypeUid; 
	
	switch (randomEventType)
	{
		case 0:
			eventTypeID = KLogCallEventTypeUid; //Voice call
			break;
		case 1:
			eventTypeID = KLogDataEventTypeUid; // Data call
			break;
		case 2:
			eventTypeID = KLogFaxEventTypeUid; // Fax call
			break;
		case 3:
			eventTypeID = KLogShortMessageEventTypeUid; // SMS call
			break;
		case 4:
			eventTypeID = KLogMailEventTypeUid; // Email
			break;
		case 5:
			eventTypeID = KLogTaskSchedulerEventTypeUid; // Task scheduler event
			break;
		default:
			User::Panic(KEngineDefaultSwitch,1);
            break; 
	}
		
	event->SetEventType(eventTypeID);
	
	event->SetSubject(KOwnEventSubject);
	
	TTime time;			// creation time from the device clock
	time.HomeTime();
	event->SetTime(time); 
	
	TBuf<KLogMaxNumberLength> number; // Randomize number
	number.AppendNum(Random(7000000));
	event->SetNumber(number);
	
	event->SetRemoteParty(KOwnEventRemoteParty); 	
	
	return event;
	}

// ----------------------------------------------------
// CLogExEngine::Random(const TInt& aLimiter)
// Creates random number
// ----------------------------------------------------
//
TInt CLogExEngine::Random(const TInt& aLimiter)
	{
	
	TTime time;
	time.HomeTime();
	TInt64 smallRandSeed=time.Int64();
	TInt number = Math::Rand(smallRandSeed)%aLimiter;
	return number;
	}

//End of file

void CLogExEngine::StopReadEvent()
{
	iTask=ESleep;
}
